//
//  OosAtomServiceCallback.m
//  Oos4ios
//
//  Created by Pablo Gonzalez on 3/23/11.
//

#import "OosAtomServiceCallback.h"
#import "../../Persistence/OosManagedContext.h"
#import "../../Atom/Feeds/OosFeed.h"

enum {
    ENTRY_TYPE,
    FEED_TYPE,
    CATEGORY_TYPE
};

@interface ParserRequest : NSObject {
    
    id parserObject;
    int type;
    
}

@property (nonatomic, retain) id parserObject;
@property (nonatomic) int type;

@end

@implementation ParserRequest

@synthesize parserObject;
@synthesize type;

@end

@implementation OosAtomServiceCallback

@synthesize ticket = mTicket;
@synthesize readCallback = mReadCallback;
@synthesize createCallback = mCreateCallback;
@synthesize updateCallback = mUpdateCallback;
@synthesize deleteCallback = mDeleteCallback;
@synthesize feedParser = mFeedParser;
@synthesize categoryParser = mCategoryParser;
@synthesize entryParser = mEntryParser;
@synthesize sizeCallback = mSizeCallback;

enum {
    WORK_TODO = 1,
    NO_WORK_TODO = 0
};

+ (OosAtomServiceCallback *) callback
{
	return [[[OosAtomServiceCallback alloc] init] autorelease];
}

- (id)init
{
    if ((self = [super init])) {
//        threadLock = [[NSConditionLock alloc] init];
//        workerThreadActive = NO;
        parserQueue = [[NSOperationQueue alloc] init];
        [parserQueue setMaxConcurrentOperationCount:1];
    }
    return self;
}

- (void)receivedCorrect
{
    id<IOosDaoCallback> callback = nil;
    if (self.readCallback) {
        callback = self.readCallback;
    } else if (self.createCallback) {
        callback = self.createCallback;
    } else if (self.updateCallback) {
        callback = self.updateCallback;
    } else if (self.deleteCallback) {
        callback = self.deleteCallback;
    } else {
        [NSException raise:@"No callback" format:@"A Dao callback is needed in the atom callback"];
        return;
    }
    if ([callback respondsToSelector:@selector(resultedCorrect:)]) {
        [callback resultedCorrect:self.ticket];
    }
}

- (void) error: (NSError *) error
{
    id<IOosDaoCallback> callback = nil;
    if (self.readCallback) {
        callback = self.readCallback;
    } else if (self.createCallback) {
        callback = self.createCallback;
    } else if (self.updateCallback) {
        callback = self.updateCallback;
    } else if (self.deleteCallback) {
        callback = self.deleteCallback;
    } else {
        [NSException raise:@"No callback" format:@"A Dao callback is needed in the atom callback"];
        return;
    }
    [callback resultedInError: error withTicket: self.ticket];
}

// stops more than one parse at a time (to avoid CoreData issues)
static NSLock *parserLock;

#pragma mark thread stuff

- (void) parseRequest: (ParserRequest *) request
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
    [NSThread currentThread].name = [NSString stringWithFormat:@"parseFeedThread%d", [NSDate timeIntervalSinceReferenceDate], nil];
//    @try {
        if (!parserLock) {
            parserLock = [NSLock new];
        }
        [parserLock lock];
        switch (request.type) {
            case FEED_TYPE:
                [mFeedParser parseFeed: request.parserObject
                          withCallback: self];
                break;
            case ENTRY_TYPE:
                [mEntryParser parseEntry: request.parserObject
                            withCallback: self];
                break;
            case CATEGORY_TYPE:
                [mCategoryParser parseCategories: request.parserObject
                                    withCallback: self];
                break;
        }
        [parserLock unlock];
//    }
//    @catch (NSException *exception) {
//        NSLog(@"exception: %@", [exception description]);
//    }
//    @finally {
        [pool release];
//    }
    
}

- (void) addParserRequest: (id) request
{
    NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self 
                                                                     selector:@selector(parseRequest:)
                                                                       object:request];
    [parserQueue addOperation:op];
    [op release];  
}

#pragma mark receivedX

- (void) received:(id) object
{
    if ([object isKindOfClass:[NSError class]]) {
        [self error:object];
    } else if (self.readCallback) {
        [self.readCallback readResult: object 
                           withTicket: self.ticket];
    } else if (self.createCallback) {
        if ([object isKindOfClass:[NSArray class]]) {
            if ([(NSArray *)object count] > 0) {
                object = [(NSArray *)object objectAtIndex:0];
            } else {
                object = nil;
            }
        }
        [self.createCallback createResult:object 
                               withTicket: self.ticket];
    } else if (self.updateCallback) {
        [self.updateCallback updatedWithTicket:self.ticket];
    } else if (self.deleteCallback) {
        [self.deleteCallback deletedWithTicket:self.ticket];
    } else {
        [NSException raise:@"No callback" format:@"A Dao callback is needed in the atom callback"];
        return;
    }
}

- (void) receivedFeed:(OosFeed *)feed
{
    if (!mFeedParser) {
        NSError *error = [NSError errorWithDomain:@"no feed parser" 
											 code:-1 
										 userInfo:nil];
		[self problemWithFetch: error];
    }
    if (mSizeCallback && [feed isKindOfClass:[OosFeed class]] 
            && [[feed startIndex] intValue] == 1) {
        [mSizeCallback size: [feed totalResults] 
                 withTicket: mTicket];
    }
    
    ParserRequest *request = [[ParserRequest new] autorelease];
    request.parserObject = feed;
    request.type = FEED_TYPE;
    [self addParserRequest:request];
}

- (void)receivedCategoryGroup:(GDataAtomCategoryGroup *)categotyGroup
{
    if (mCategoryParser) {

        ParserRequest *request = [[ParserRequest new] autorelease];
        request.parserObject = categotyGroup;
        request.type = CATEGORY_TYPE;
        [self addParserRequest:request];
    } else {
        NSError *error = [NSError errorWithDomain:@"no category parser" 
											 code:-1 
										 userInfo:nil];
		[self problemWithFetch: error];
    }
}

- (void)receivedEntry:(id)entry
{
    if (mEntryParser) {
        ParserRequest *request = [[ParserRequest new] autorelease];
        request.parserObject = entry;
        request.type = ENTRY_TYPE;
        [self addParserRequest:request];
    } else {
        NSError *error = [NSError errorWithDomain:@"no entry parser" 
											 code:-1 
										 userInfo:nil];
		[self problemWithFetch: error];
    }
}
	 
- (void) problemWithFetch:(NSError *)error
{
    if ([error code] == 404) {
        NSArray *emptyArray = [NSArray array];
        [self received:emptyArray];
    } else {
        [self error:error];
    }
}

- (void)dealloc
{
    [mCategoryParser release];
    [mEntryParser release];
    [mFeedParser release];
    [mTicket release];
    [mSizeCallback release];
    
    [parserQueue release];
    
    [super dealloc];
}

@end
